package core

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"
	"zinx_websokect_poker/zinx_app/poker_game/card"
	"zinx_websokect_poker/zinx_app/poker_game/http"
	json2 "zinx_websokect_poker/zinx_app/poker_game/json"
	"zinx_websokect_poker/zinx_app/poker_game/log"
	"zinx_websokect_poker/zinx_app/poker_game/model"
	"zinx_websokect_poker/zinx_app/poker_game/protocol"
)

type UpdateDetailsPostData struct {
	RoomID    string `json:"roomId"`
	GameID    string `json:"gameId"`
	GameState int    `json:"gameState"`
	AllCount  int    `json:"allCount"`
	IsQuick   int    `json:"isQuick"`
	SbUserID  int    `json:"sbUserId"`
	ShowPokes []int  `json:"showPokes"`
	Users     []UpdateDetailsUser `json:"users"`
}

type UpdateDetailsUser struct {
UserID       int64 `json:"userId"`
Position     int   `json:"position"`
CurrentChips int   `json:"currentChips"`
Pokes        []int `json:"pokes"`
IsGiveUp     int   `json:"isGiveUp"`
IsSitUp      int   `json:"isSitUp"`
IsSb         int   `json:"isSb"`
Level        int   `json:"level"`
IsDepend     int   `json:"isDepend"`
IsWinner     int   `json:"isWinner,omitempty"`
Chips        int   `json:"chips,omitempty"`
IsAllIn      int   `json:"isAllIn,omitempty"`
WinnerPokes  []int `json:"winnerPokes,omitempty"`
}

//更新对局详情
func (r *Room) UpdateGamedDetails(IsQuick bool, sb *Occupant, gameId string){
	quick := 0

	if IsQuick {
		quick = 1
	}

	var ud []UpdateDetailsUser
	for _, o := range r.Occupants {
		if o == nil {
			continue
		}
		IsGiveUp := 1
		isWinner := 0
		IsDepend := 0
		IsSb 	 := 0
		IsAllIn  := 0
		var winnerPokes []int
		if r.Button == o.Pos {
			IsDepend = 1
		}
		if sb.Pos == o.Pos {
			IsSb = 1
		}
		if o.IsGameing() {
			IsGiveUp = 0
		}
		if 0 == o.chips {
			IsAllIn = 1
		}

		for _, winner := range r.winners {
			if winner.Pid == o.Pid{
				isWinner = 1
				winnerPokes = o.show.Value
			}
		}

		detail := UpdateDetailsUser{
			UserID: o.OutId,
			Position: int(o.Pos),
			CurrentChips: int(o.Bet),
			Pokes: o.cards.GetValues(),
			IsGiveUp: IsGiveUp,
			IsSitUp: 0,
			IsSb: IsSb,
			Level: int(o.show.Type),
			IsDepend: IsDepend,
			IsWinner: isWinner,
			Chips: int(o.chips),
			WinnerPokes: winnerPokes,
			IsAllIn: IsAllIn,
		}
		ud = append(ud, detail)
	}
	//sbUserID := sb.OutId
	//if sbPos > 0 && r.Occupants[sbPos-1] != nil {
	//	sbUserID = int(r.Occupants[sbPos-1].OutId)
	//}

	var pot = r.getPot()
	uu := &UpdateDetailsPostData{
		RoomID:    r.Number,
		GameID:    gameId,
		GameState: r.GameState,
		AllCount:  int(pot),
		IsQuick:   quick,
		SbUserID:  int(sb.OutId),
		ShowPokes: r.Cards.GetValues(),
		Users:     ud,
	}

	js,_:=json.Marshal(uu)
	http.UpdateGameMatchDetails(string(js))

}

func (r *Room) getPot() uint32{
	pots := r.calc()
	var pot uint32 = 0
	for _, u := range pots {
		pot += u.Pot
	}
	return pot
}

//结束对局发送信息到后台
func (r *Room) endGameMatch(sbPos uint8,bbPos uint8,gameID string) []*protocol.MatchDetails{
	var pot = r.getPot()
	var sbUserID int64 = 0
	var bbUserID int64 = 0
	var dependUserID int64 = 0
	var showPokes = make([]int, 5)
	if r.Occupants[sbPos-1] != nil {
		sbUserID = r.Occupants[sbPos-1].OutId
	}

	if r.Occupants[bbPos-1] != nil {
		bbUserID = r.Occupants[bbPos-1].OutId
	}

	if r.Occupants[r.Button-1] != nil {
		dependUserID = r.Occupants[r.Button-1].OutId
	}

	if r.Cards != nil {
		showPokes = r.Cards.GetValues()
	}

	var mds = make([]*protocol.MatchDetails, 0)
	var users = make([]protocol.Users, 0, r.Max)

	//for _, occupant := range r.Occupants {
	//	if occupant == nil {
	//		continue
	//	}
	//	user := protocol.Users{}
	//	level := 1
	//	isWinner := 0
	//	for _, winner := range r.winners {
	//		if winner.Pos == occupant.Pos{
	//			isWinner = 1
	//		}
	//	}
	//	var winnerPokes = make([]int, 5)
	//	if occupant.show != nil {
	//		level = int(occupant.show.Type)
	//		winnerPokes = occupant.show.Value
	//	}
	//	user.UserID = int(occupant.OutId)
	//	user.Position = int(occupant.Pos)
	//	user.CurrentChips = int(occupant.Bet)
	//	user.Pokes = occupant.cards.GetValues()
	//	user.Level = level
	//	user.Chips = int(occupant.chips)
	//	user.IsWinner = isWinner
	//	user.WinnerPokes = winnerPokes
	//	users = append(users, user)
	//}

	for i, occupant := range r.staticOccupants {
		if occupant.IsEmpty() {
			continue
		}
		//座位上的玩家存在，则取座位上的数据，否则取最后留下的数据
		if r.Occupants[i] != nil {
			occupant = *r.Occupants[i]
		}

		user := protocol.Users{}
		level := 1
		isWinner := 0
		for _, winner := range r.winners {
			if winner.Pos == occupant.Pos{
				isWinner = 1
			}
		}
		var winnerPokes = make([]int, 5)
		if occupant.show != nil {
			level = int(occupant.show.Type)
			winnerPokes = occupant.show.Value
		}
		user.UserID = int(occupant.OutId)
		user.Position = int(occupant.Pos)
		user.CurrentChips = int(occupant.Bet)
		user.Pokes = occupant.cards.GetValues()
		user.Level = level
		user.Chips = int(occupant.chips)
		user.IsWinner = isWinner
		user.WinnerPokes = winnerPokes
		users = append(users, user)
	}
	r.Each(0, func(o *Occupant) bool {
		isNext := 0
		if n := r.next(o.Pos); n != nil {
			isNext = int(n.Pos)
		}
		isAllIn:= 0
		if o.chips == 0{
			isAllIn = 1
		}
		md := &protocol.MatchDetails{
			State:    r.GameState,
			AllCount: int(pot),
			Uid: 	  int(o.OutId),
			Sb:       int(r.SB),
			Bb:       int(r.BB),
			SbUserID: int(sbUserID),
			BbUserID: int(bbUserID),
			DependUserID: int(dependUserID),
			ShowPokes: showPokes,
			Users: users,
			BaseChip: 0,
			IsNext: int(isNext),
			IsCurrent: int(o.Pos),
			Value: int(o.Bet),
			CanPass: 1,
			FollowBet: 0,
			CurrentChip: int(r.Bet),
			IsAllIn: isAllIn,
		}
		mds = append(mds, md)
		return true
	})

	//js,_:=json.Marshal(mds)
	//http.EndGameMatch(r.Number, gameID, string(js))
	return mds
}

//游戏入口
func (r *Room) StartDelay(s interface{}) {
	//startDelay *startDelay, o *Occupant
	startDelay := s.(*StartDelay)
	if startDelay.kind == 0 {
		//r.Info()
		log.Info("Game-StartDelay","【启动游戏】房间号：" + r.Number)
		r.start()
	}
}

func (r *Room) start() {
	if !r.StartAble {
		//启动标志为false，代表倒计时的时间到，清理房间。
		log.Info("Room-TimeOut", "【解散房间】房间超时，房间号：" + r.Number)
		r.ClearRoom()
		return
	}
	if r.status == RUNNING {
		return
	}
	//初始化游戏信息
	r.Cards = nil
	for i, _ := range r.Chips {
		r.Chips[i] = 0
	}
	r.sbPos = 0
	r.bbPos = 0
	// 产生庄
	var dealer *Occupant

	for i, _ := range r.Occupants {
		if r.Occupants[i] != nil {
			r.Occupants[i].SetGameing()
		}
	}



	r.remain = 0
	r.allin = 0
	r.isAllin = false
	r.CurrentChip = 0
	// 剔除筹码小于大盲和离线的玩家

	n := 0
	fmt.Println("房间的大盲为：", r.BB)
	r.Each(0, func(o *Occupant) bool {
		fmt.Println("玩家的筹码为：",o.Nickname, o.chips )
		if o.chips < r.BB || o.IsOffline() {
			o.SetSitdown()
			return true
		}
		o.SetGameing()
		n ++
		o.currentChips = make([]uint32,6)
		o.gameActions = make([]protocol.UserAction, 0)
		return true
	})

	button := r.Button - 1
	r.Each((button+1)%r.Cap(), func(o *Occupant) bool {
		r.Button = o.Pos
		dealer = o
		return false
	})

	if dealer == nil {
		return
	}

	fmt.Println("庄家的座位号是：", r.Button)

	fmt.Println("庄家是：", dealer.Nickname)
	fmt.Println("游戏准备开始")
	// 2人及以上才开始游戏
	if n < 2 {
		fmt.Println("2人及以上才开始游戏",n)
		log.Info("Game-StartDelay","【启动游戏失败】房间号：" + r.Number + "，2人及以上才开始游戏")
		return
	}

	//准备
	r.ready()

	//结束对局详情
	var mds = make([]*protocol.MatchDetails, 0)

	// 洗牌
	dz := card.NewDZPK()
	//gameID
	gameID := http.GetRandomString(10)

	// 产生小盲
	if n := r.next(dealer.Pos); n == nil {
		fmt.Println("无法产生小盲")
		log.Info("Game-Start","【启动游戏失败】房间号：" + r.Number + "，无法产生小盲.")
		return
	}
	sb := r.next(dealer.Pos)
	r.sbPos = sb.Pos
	if n == 2 { // one-to-one 一对一设置小盲为庄家
		sb = dealer
	}
	// 产生大盲
	bb := r.next(sb.Pos)
	r.bbPos = bb.Pos

	//收集每阶段用户操作数据
	mds = append(mds, r.endGameMatch(r.sbPos,r.bbPos,gameID)...)

	// Round 1 : preflop
	r.GameState = Round1
	fmt.Printf("Round 1 :")
	log.Info("Game-Start","【Round 1】房间号：" + r.Number + "游戏编号：" + gameID)
	r.betFlag = false
	r.order = 0

	// 小大盲下注
	r.betting(sb, int32(r.SB), 1)
	r.betting(bb, int32(r.BB), 1)

	//直接发九家牌
	dz.Dealcard(9)
	userinfos := make([]*protocol.UserSeat, r.Cap()+1, r.Cap()+1)
	r.Each(0, func(o *Occupant) bool {
		userSeat := &protocol.UserSeat{
			Chips: o.preGameChips,
			CurrentChips: o.currentChips,
			IsAllIn: false,
			IsGiveUp: false,
			IsSitUp: false,
			UserId: o.OutId,
			Position: o.Pos,
			Actions: nil,
		}
		userinfos[o.Pos] = userSeat
		return true
	})
	var brc []byte
	r.Each(0, func(o *Occupant) bool {
		o.cards = dz.PHandCardList[o.Pos-1]
		//发送牌和牌型给玩家
		var nextPos uint8
		if n := r.next(bb.Pos) ;n != nil {
			nextPos = n.Pos
		}

		//牌型
		cards := o.cards
		level := cards.GetCombination().Type
		o.show = cards.GetCombination()
		pot := r.getPot()
		gameresp := &protocol.StartGameResp{
			AllCount: pot,
			BaseChip: r.BB,
			CurrentChip: r.CurrentChip,
			Depend: r.Button,
			FollowBet: r.Bet - o.Bet,
			GameState: r.GameState,
			IsBb: bb.Pos,
			IsSb: sb.Pos,
			IsNext: nextPos,//下一位投注玩家位置
			Level: int(level),
			Pokes: o.cards.GetValues(),//牌值数组
			Mult:  2,
			Seats: userinfos,
		}
		js := json2.Jsonmr(51,gameresp)
		brc = js
		o.WriteMsg(js)
		//if r.remain > 1 && r.allin+1 < r.remain && o.Pos == nextPos {
		//	// 需要等待玩家响应的下注请求
		//	go o.GetActionResponse(js)
		//}else {
		//	o.WriteMsg(js)
		//}
		//o.WriteMsg([]byte(o.cards.Tostr()))
		return true
	})
	//把游戏信息广播给游客
	r.Broadcast(brc, false, r.GetAllPid()...)

	// 从大盲注的下一位开始下注
	var r1 uint8
	if n := r.next(bb.Pos) ;n != nil {
		r1 = n.Pos
	}else {
		// 无法获取到大盲注的下一位，未知错误，结束游戏。
		log.Error("Game-Start","【Round 1】房间号：" + r.Number + "无法获取到大盲注的下一位，未知错误，结束游戏。")
		fmt.Println("无法获取到大盲注的下一位，未知错误，结束游戏。")
		goto showdown
	}

	fmt.Println("Round1: r.CurrentChip", r.CurrentChip)

	r.action(r1)

	if r.remain <= 1 {
		fmt.Println("场上人数少于等于1游戏结束")
		fmt.Println("回合一结束")
		goto showdown
	}

	//添加对局详情
	r.UpdateGamedDetails(false, sb, gameID)
	//收集每阶段用户操作数据
	mds = append(mds, r.endGameMatch(r.sbPos,r.bbPos,gameID)...)

	// Round 2 : Flop
	r.GameState = Round2
	r.Mult = -1
	r.betFlag = false
	r.order = 0
	fmt.Println("Round 2")
	log.Info("Game-Start","【Round 2】房间号：" + r.Number + "游戏编号：" + gameID)

	for i, userinfo := range userinfos {
		if userinfo != nil {
			if r.Occupants[i-1] == nil{
				//userinfos[i].Actions = nil
				userinfos[i].IsGiveUp = true
				userinfos[i].IsSitUp = true
			}else {
				userinfos[i].Chips = r.Occupants[i-1].preGameChips
				userinfos[i].CurrentChips = r.Occupants[i-1].currentChips
				if r.Occupants[i-1].chips == 0 {
					userinfos[i].IsAllIn = true
				}
				if !r.Occupants[i-1].IsGameing() {
					userinfos[i].IsGiveUp = true
				}
				userinfos[i].Actions = r.Occupants[i-1].gameActions
			}
		}
	}

	//公共牌
	r.Cards = dz.PUnderCardFlop
	r.Each(0, func(o *Occupant) bool {
		var cs = make(card.TCards, 3)
		copy(cs, r.Cards)
		cs = append(cs, o.cards...)
		o.show = cs.GetCombination()
		level := o.show.Type
		var pos = r.nextBetPos(r.Button)
		//if n := r.next(r.Button);n != nil {
		//	pos = n.Pos
		//}
		pot := r.getPot()
		//封装消息发送给对应的玩家
		gameresp := &protocol.Round2Resp{
			AllCount: pot,
			BaseChip: r.BB,
			CanPass: true,
			GameState: r.GameState,
			IsAllIn: r.isAllin,
			IsCurrent: o.Pos,
			//Value: r.PreBet,
			Value: 0,
			Level: int(level),
			IsNext: pos,//下一位投注玩家位置
			ShowPokes: dz.PUnderCardList.GetValues(),
			ShowChipType: r.UserAction.ShowChipType,
			AddChip: r.UserAction.AddChip,
			Action: r.UserAction.Action,
			Order: r.UserAction.Order,
			Seats: userinfos,
		}
		js := json2.Jsonmr(53,gameresp)
		brc = js
		o.WriteMsg(js)
		return true
	})

	//把游戏信息广播给游客
	r.Broadcast(brc, false, r.GetAllPid()...)

	r.action(0)

	//等待信号进入下阶段，或延时2秒
	//r.GetReqRound2(time.Second * 4)
	time.Sleep(time.Second * 2)

	if r.remain <= 1 {
		fmt.Println("场上人数少于等于1游戏结束")
		fmt.Println("回合二结束")
		goto showdown
	}

	//添加对局详情
	r.UpdateGamedDetails(false, sb, gameID)
	//收集每阶段用户操作数据
	mds = append(mds, r.endGameMatch(r.sbPos,r.bbPos,gameID)...)

	// Round 3 : Turn
	fmt.Println("Round 3")
	log.Info("Game-Start","【Round 3】房间号：" + r.Number + "游戏编号：" + gameID)

	for i, userinfo := range userinfos {
		if userinfo != nil {
			if r.Occupants[i-1] == nil{
				//userinfos[i].Actions = nil
				userinfos[i].IsGiveUp = true
				userinfos[i].IsSitUp = true
			}else {
				userinfos[i].Chips = r.Occupants[i-1].preGameChips
				userinfos[i].CurrentChips = r.Occupants[i-1].currentChips
				if r.Occupants[i-1].chips == 0 {
					userinfos[i].IsAllIn = true
				}
				if !r.Occupants[i-1].IsGameing() {
					userinfos[i].IsGiveUp = true
				}
				userinfos[i].Actions = r.Occupants[i-1].gameActions
			}
		}
	}

	r.GameState = Round3
	r.betFlag = false
	r.order = 0
	//公共牌
	r.Cards = append(r.Cards, dz.PUnderCardTurn...)
	fmt.Println("Round 3", r.Cards.Tostr())
	r.Each(0, func(o *Occupant) bool {
		var cs = make(card.TCards, 4)
		copy(cs, r.Cards)
		cs = append(cs, o.cards...)
		o.show = cs.GetCombination()
		level := o.show.Type
		var pos = r.nextBetPos(r.Button)
		//if n := r.next(r.Button);n != nil {
		//	pos = n.Pos
		//}
		pot := r.getPot()
		//封装消息发送给对应的玩家
		gameresp := &protocol.Round3Resp{
			AllCount: pot,
			BaseChip: r.BB,
			CanPass: true,
			GameState: r.GameState,
			IsAllIn: r.isAllin,
			IsCurrent: o.Pos,
			//Value: r.PreBet,
			Value: 0,
			Level: int(level),
			IsNext: pos,//下一位投注玩家位置
			ShowPokes: dz.PUnderCardList.GetValues(),
			ShowChipType: r.UserAction.ShowChipType,
			AddChip: r.UserAction.AddChip,
			Action: r.UserAction.Action,
			Order: r.UserAction.Order,
			Seats: userinfos,
		}
		js := json2.Jsonmr(54,gameresp)
		o.WriteMsg(js)
		brc = js
		return true
	})

	//把游戏信息广播给游客
	r.Broadcast(brc, false, r.GetAllPid()...)

	//等待信号进入下阶段，或延时2秒
	//r.GetReqRound3(time.Second * 4)
	time.Sleep(time.Second * 2)

	r.action(0)
	if r.remain <= 1 {
		fmt.Println("场上人数少于等于1游戏结束")
		fmt.Println("回合三结束")
		goto showdown
	}

	//添加对局详情
	r.UpdateGamedDetails(false, sb, gameID)
	//收集每阶段用户操作数据
	mds = append(mds, r.endGameMatch(r.sbPos,r.bbPos,gameID)...)

	//Round 4
	fmt.Println("Round 4")
	log.Info("Game-Start","【Round 4】房间号：" + r.Number + "游戏编号：" + gameID)

	for i, userinfo := range userinfos {
		if userinfo != nil {
			if r.Occupants[i-1] == nil{
				//userinfos[i].Actions = nil
				userinfos[i].IsGiveUp = true
				userinfos[i].IsSitUp = true
			}else {
				userinfos[i].Chips = r.Occupants[i-1].preGameChips
				userinfos[i].CurrentChips = r.Occupants[i-1].currentChips
				if r.Occupants[i-1].chips == 0 {
					userinfos[i].IsAllIn = true
				}
				if !r.Occupants[i-1].IsGameing() {
					userinfos[i].IsGiveUp = true
				}
				userinfos[i].Actions = r.Occupants[i-1].gameActions
			}
		}
	}

	r.GameState = Round4
	r.betFlag = false
	r.order = 0
	//公共牌
	r.Cards = append(r.Cards, dz.PUnderCardRiver...)
	fmt.Println("Round 4", r.Cards.Tostr())
	r.Each(0, func(o *Occupant) bool {
		var cs = make(card.TCards, 5)
		copy(cs, r.Cards)
		cs = append(cs, o.cards...)
		fmt.Println("Round 4,玩家的牌组", cs.Tostr())
		o.show = cs.GetCombination()
		level := o.show.Type
		//var pos uint8 = 0
		var pos = r.nextBetPos(r.Button)
		//if n := r.next(r.Button);n != nil {
		//	pos = n.Pos
		//}
		pot := r.getPot()
		//封装消息发送给对应的玩家
		gameresp := &protocol.Round3Resp{
			AllCount: pot,
			BaseChip: r.BB,
			CanPass: true,
			GameState: r.GameState,
			IsAllIn: r.isAllin,
			IsCurrent: o.Pos,
			Value: 0,
			//Value: r.PreBet,
			Level: int(level),
			IsNext: pos,//下一位投注玩家位置
			ShowPokes: dz.PUnderCardList.GetValues(),
			ShowChipType: r.UserAction.ShowChipType,
			AddChip: r.UserAction.AddChip,
			Action: r.UserAction.Action,
			Order: r.UserAction.Order,
			Seats: userinfos,
		}

		js := json2.Jsonmr(55,gameresp)
		o.WriteMsg(js)
		brc = js
		return true
	})
	//把游戏信息广播给游客
	r.Broadcast(brc, false, r.GetAllPid()...)

	//等待信号进入下阶段，或延时2秒
	//r.GetReqRound4(time.Second * 2)

	r.action(0)
	//添加对局详情
	r.UpdateGamedDetails(false, sb, gameID)

showdown:
	// todo 比牌
	log.Info("Game-Start","【Result】房间号：" + r.Number + "游戏编号：" + gameID)

	r.status = GAMEOVER
	r.GameState = Result
	isQuick := false
	pot := r.getPot()

	if r.remain > 1 {
			r.showdown()
		}else{
			r.showdown2()
			isQuick = true
		}

	//userinfos = make([]*protocol.UserSeat, 10, 10)

	for i, userinfo := range userinfos {
		if userinfo != nil {
			if r.Occupants[i-1] == nil{
				//userinfos[i].Actions = nil
				userinfos[i].IsGiveUp = true
				userinfos[i].IsSitUp = true
			}else {
				if len(r.Occupants[i-1].cards) >=2 {
					userinfos[i].Pokes = r.Occupants[i-1].cards.GetValues()
				}
				userinfos[i].Chips = r.Occupants[i-1].preGameChips
				userinfos[i].CurrentChips = r.Occupants[i-1].currentChips
				if r.Occupants[i-1].chips == 0 {
					userinfos[i].IsAllIn = true
				}
				if !r.Occupants[i-1].IsGameing() {
					userinfos[i].IsGiveUp = true
				}
				userinfos[i].Actions = r.Occupants[i-1].gameActions
				userinfos[i].WinnerChips = int(r.Occupants[i-1].chips) - int(r.Occupants[i-1].preGameChips)
			}
		}
	}

	var winner []int
	var winnerPokes [][]int
	for _, w := range r.winners {
		winner = append(winner, int(w.Pos))
		winnerPokes = append(winnerPokes, w.show.Value)
	}

	gameresp := &protocol.ResultResp{
		AllCount: pot,
		BaseChip: r.BB,
		GameSeats: userinfos,
		GameState: r.GameState,
		IsCurrent: r.BetPos,
		//Value: r.Bet,
		Value: 0,
		IsQuick: isQuick,
		SbUserId: sb.OutId,
		Winner: winner,
		WinnerPokes: winnerPokes,
		ShowPokes: r.Cards.GetValues(),
		ShowChipType: r.UserAction.ShowChipType,
		AddChip: r.UserAction.AddChip,
		Action: r.UserAction.Action,
		Order: r.UserAction.Order,
	}
	brc = json2.Jsonmr(56,gameresp)
	r.Broadcast(brc, true)

	//添加对局详情
	r.UpdateGamedDetails(isQuick, sb, gameID)
	//结束对局收集每阶段用户操作数据
	mds = append(mds, r.endGameMatch(r.sbPos,r.bbPos,gameID)...)
	js,_:=json.Marshal(mds)
	http.EndGameMatch(r.Number, gameID, string(js))
	// =============================
	//游戏结束，玩家状态设为坐下
	for _, o := range r.Occupants {
		if o != nil && o.IsGameing() {
			o.SetSitdown()
		}
	}

	fmt.Println("游戏结束")

	time.AfterFunc(time.Second*6, func() {
		r.StartDelay(&StartDelay{})
	})

}

func (r *Room) betting(o *Occupant, n int32, auto int) (raised bool) {
	if n > int32(o.chips) || // 手上筹码不足
		(n == 0 && o.Bet != r.Bet) || // 让牌
		(n > 0 && n != int32(o.chips) && ((n + int32(o.Bet)) < int32(r.Bet))) {
		//glog.Errorf("下注筹码不合法!!！ n:%d  p.Bet:%d  p.Chips:%d  t.Bet:%d", n, o.Bet, o.chips, r.Bet)
		fmt.Printf("下注筹码不合法!!！ n:%d  p.Bet:%d  p.Chips:%d  t.Bet:%d", n, o.Bet, o.chips, r.Bet)
		deb := fmt.Sprintf("下注筹码不合法!!！ n:%d  p.Bet:%d  p.Chips:%d  t.Bet:%d", n, o.Bet, o.chips, r.Bet)
		log.Debug("Game-betting","玩家："+ o.Nickname + "，OutId :" +strconv.Itoa(int(o.OutId)) +
			"【下注动作】" + deb )
		n = -1
	}
	r.order ++
	//记录玩家投注动作
	gameBet := Check
	//筹码动画执行
	showChipType := 0
	//第一回合时展示加注用的属性
	showFourBB := false

	var addChip int32

	if o.currentChips[r.GameState] == 0 && n <= 0 {
		showChipType = NoShow
	}

	if o.currentChips[r.GameState] == 0 && n > 0 {
		showChipType = ShowChip
	}

	if o.currentChips[r.GameState] > 0 && n > 0 {
		showChipType = AddShowChip
		addChip = n
	}

	r.PreBet = uint32(n)
	o.currentChips[r.GameState] += uint32(n)
	value := n
	isCurrent := o.Pos
	var isEnd uint8
	if r.GameState != Round1 && r.BetPrePos == isCurrent {
		isEnd = 1
	}
	if r.GameState == Round1 {
		//加过注，isEnd为BetPrePos
		if r.Bet > r.BB {
			if r.BetPrePos == isCurrent{
				isEnd = 1
			}
		}else {
			//没加注，isEnd为Button
			if r.BetPrePos == r.Button{
				isEnd = 1
			}
		}
	}
	actionName := ""
	if n < 0 {
		//弃牌
		actionName = model.BET_FOLD
		gameBet = GiveUp
		n = 0
		r.remain--
	} else if n == 0 {
		//让牌
		gameBet = Check
		actionName = model.BET_CHECK
	} else if uint32(n)+o.Bet <= r.Bet {
		//跟注
		gameBet = Follow
		actionName = model.BET_CALL
		if o.chips < uint32(n) {
			o.chips = 0
		}else {
			o.chips -= uint32(n)
		}
		o.Bet += uint32(n)
	} else {
		//加注
		gameBet = AddBet
		actionName = model.BET_RAISE
		if o.chips < uint32(n) {
			o.chips = 0
		}else {
			o.chips -= uint32(n)
		}
		o.Bet += uint32(n)
		r.Bet = o.Bet
		r.BetPos = o.Pos
		r.CurrentChip = r.Bet
		isEnd = 0
		if auto == 0 {
			raised = true
		}
	}

	if n > 0 && !r.betFlag {
		gameBet = Bet
		r.betFlag = true
	}

	if r.GameState == Round1 && r.Bet == r.BB {
		showFourBB = true
	}

	if r.GameState == Round1 && actionName == model.BET_RAISE {
		r.Mult ++
	}

	if o.chips == 0 {
		//全下
		r.allin++
		actionName = model.BET_ALLIN
		gameBet = AllIn
	}
	if o.Pos < 1 {
		return false
	}

	r.Chips[o.Pos-1] += uint32(n)

	action := protocol.UserAction{
		Action: gameBet,
		ShowChipType: showChipType,
		Value: uint32(value),
		Order: r.order,
		State: r.GameState,
		AddChip: uint32(addChip),
	}
	o.gameActions = append(o.gameActions, action)

	userinfos := make([]*protocol.UserSeat, r.Cap()+1, r.Cap()+1)
	r.Each(0, func(oo *Occupant) bool {
		IsAllIn := false
		if oo.chips == 0 {
			IsAllIn = true
		}
		userSeat := &protocol.UserSeat{
			Chips: oo.preGameChips,
			CurrentChips: oo.currentChips,
			IsAllIn: IsAllIn,
			IsGiveUp: false,
			IsSitUp: false,
			UserId: oo.OutId,
			Position: oo.Pos,
			Actions: oo.gameActions,
		}
		userinfos[oo.Pos] = userSeat
		return true
	})

	var pos = r.nextBetPos(o.Pos)
	//底池
	pot := r.getPot()
	var js []byte
	r.Each(0, func(oo *Occupant) bool {
		if auto == 1 {
			return false
		}
		if isEnd == 1 {
			//保存最后一个玩家的动作不广播，留到下一阶段开始广播.
			r.UserAction = action
			return false
		}
		followBet := r.Bet - oo.Bet
		var canPass bool
		if followBet == 0 {
			canPass = true
		}
		if r.remain <= 1 {
			pos = r.nextBetPos(oo.Pos)
		}
		js = json2.Jsonmr(52, &protocol.BetBroadcastResp{
			AllCount: pot,
			BaseChip: r.BB,
			CanPass: canPass,
			CurrentChip: r.CurrentChip,
			FollowBet: followBet,
			GameState: r.GameState,
			IsAllIn: r.isAllin,
			IsCurrent: isCurrent,
			Value: value,
			IsNext: pos,//下一个下注的玩家
			IsEnd: isEnd,//是否为当前阶段最后一个下注
			Mult: r.Mult,
			ShowFourBB: showFourBB,
			ShowChipType: showChipType,
			AddChip: uint32(addChip),
			Action: gameBet,
			Order: r.order,
			Seats: userinfos,
		})

		oo.WriteMsg(js)

		//if r.remain > 1 && r.allin+1 < r.remain && oo.Pos == pos && 0 == isEnd {
		//	// 需要等待玩家响应的下注请求
		//	go oo.GetActionResponse(js)
		//}else {
		//	oo.WriteMsg(js)
		//}

		return true
	})

	//弃牌设为坐下
	if actionName == model.BET_FOLD{
		o.SetSitdown()
	}

	r.Broadcast(js,false, r.GetAllPid()...)

	info := fmt.Sprintf("【下注动作】：%s,【下注金额】：%d",actionName,n)
	log.Info("Game-betting","玩家："+ o.Nickname + "，OutId :" +strconv.Itoa(int(o.OutId)) +
		info  )

	return
}

func (r *Room) ready() {
	r.Bet = 0
	r.BetPos = 0
	r.status = RUNNING
	r.GameState = SetDepend
	r.IsBegin = BEGIN
	r.Mult = 2
	//r.reqRound2 = make(chan int)
	//r.reqRound3 = make(chan int)
	//r.reqRound4 = make(chan int)
	//r.reqResult = make(chan int)
	r.Each(0, func(o *Occupant) bool {
		o.Bet = 0
		o.waitAction = false
		o.preGameChips = o.chips
		if o.IsGameing() {
			r.remain++
		}
		//o.HandValue = 0
		return true
	})
}

//玩家比牌
func (r *Room) showdown(){
	//清空房间的胜利者列表
	r.winners = r.winners[:0]

	pots := r.calc()

	for i, _ := range r.Chips {
		r.Chips[i] = 0
	}

	for _, pot := range pots {
		var maxO *Occupant
		for _, pos := range pot.OPos {
			o := r.Occupants[pos-1]
			//取出最大牌型的玩家放进maxO中，供下面决出胜者
			if o != nil && len(o.cards) > 0 && o.IsGameing(){
				if maxO == nil {
					maxO = o
					continue
				}
				//比对玩家手牌
				if card.Showdown(o.show, maxO.show) {
					maxO = o
				}
			}
		}

		var winners []uint8
		if maxO == nil {
			fmt.Println("!!!no maxO!!!",r.remain)
			return
		}
		for _, pos := range pot.OPos {
			o := r.Occupants[pos-1]
			if o == nil {
				continue
			}
			//maxO 为玩家中最大的牌型拥有者，遍历玩家组，取出点数相同的玩家为胜者
			//当前玩家牌型与最大牌型比对
			flag2 := card.IntTypeEqual(o.show.Type, maxO.show.Type)
			//当前玩家牌点数与最大牌点数比对
			flag  := card.IntSliceEqual(o.show.Point, maxO.show.Point)
			if flag && flag2 && o.IsGameing() {
				winners = append(winners, o.Pos)
				r.winners = append(r.winners, o)
				fmt.Println("胜利者：", o.show)
			}
		}

		if len(winners) == 0 {
			//glog.Errorln("!!!no winners!!!")
			fmt.Println("!!!no winners!!!",r.remain)
			return
		}

		for _, winner := range winners {
			r.Chips[winner-1] += pot.Pot / uint32(len(winners))
		}
		r.Chips[winners[0]-1] += pot.Pot % uint32(len(winners)) // odd chips
	}

	for i, _ := range r.Chips {
		if r.Occupants[i] != nil && r.Chips[i] > 0 {
			//房主收取手续费
			sc := r.Chips[i] * uint32(r.ServiceCharge) / 100
			if sc == 0 {
				sc = 1
			}

			//房主胜利
			if r.OwnerOc.OutId == r.Occupants[i].OutId {
				r.Occupants[i].chips += r.Chips[i]
			}else {
				r.Occupants[i].chips += r.Chips[i] - sc
				r.OwnerOc.chips += sc
			}


		}
	}
}

//玩家弃牌剩一个
func (r *Room) showdown2(){
	//清空房间的胜利者列表
	r.winners = r.winners[:0]

	pots := r.calc()
	for i, _ := range r.Chips {
		r.Chips[i] = 0
	}
	var winners []uint8
	for _, pot := range pots {
		for _, pos := range pot.OPos {
			o := r.Occupants[pos-1]
			if o != nil && o.IsGameing() {
				winners = append(winners, o.Pos)
				r.winners = append(r.winners, o)
			}
		}
		if len(winners) == 0 {
			//glog.Errorln("!!!no winners!!!")
			fmt.Println("!!!no winners!!!")
			return
		}

		for _, winner := range winners {
			fmt.Println("胜利者：", winner)
			r.Chips[winner-1] += pot.Pot / uint32(len(winners))
		}
		r.Chips[winners[0]-1] += pot.Pot % uint32(len(winners)) // odd chips
	}

	for i, _ := range r.Chips {
		if r.Occupants[i] != nil && r.Chips[i] > 0 {
			//房主收取手续费
			sc := r.Chips[i] * uint32(r.ServiceCharge) / 100
			if sc == 0 {
				sc = 1
			}
			//房主胜利
			if r.OwnerOc.OutId == r.Occupants[i].OutId {
				r.Occupants[i].chips += r.Chips[i]
			}else {
				r.Occupants[i].chips += r.Chips[i] - sc
				r.OwnerOc.chips += sc
			}

		}
	}
}

func (r *Room) calc() (pots []handPot) {
	pots = calcPot(r.Chips)
	r.Pot = r.Pot[:]
	var ps []uint32
	for _, pot := range pots {
		r.Pot = append(r.Pot, pot.Pot)
		ps = append(ps, pot.Pot)
	}
	//通报奖池
	//r.Broadcast(&protocol.Pot{Pot: ps}, true)
	fmt.Println("通报奖池", &protocol.Pot{Pot: ps})
	return
}

func (r *Room) action(pos uint8) {
	r.CurrentChip = 0

	if r.allin+1 >= r.remain {
		r.isAllin = true
		return
	}
	var skip uint8
	if pos == 0 { // start from left hand of button
		pos = (r.Button)%r.Cap() + 1
	}

	for {
		//加注标志
		var raised uint8
		if la := r.last(pos); la != nil {
			r.BetPrePos = r.last(pos).Pos
		}
		//下注循环
		r.Each(pos-1, func(o *Occupant) bool {
			// 场上人数小于等于1时，结束下注动作
			if r.remain <= 1 || !o.IsGameing() {
				return false
			}
			// 当前位置玩家跳过下注或者筹码为0时，结束下注动作
			if o.Pos == skip || o.chips == 0 {
				return true
			}
			//保存当前下注玩家的座位号
			r.Current = o.Pos
			// 等待下注动作channel
			n := o.GetAction(r.Timeout)
			if r.remain <= 1 {
				return false
			}
			// 调用下注操作，o为当前玩家对象，n是下注金额
			if r.betting(o, n, 0) {
				//如果有玩家加注，则开始新的循环
				raised = o.Pos
				return false
			}
			return true
		})
		//没人加注则退出死循环，有加注则继续循环下注。
		if raised == 0 {
			r.CurrentChip = 0
			break
		}
		pos = raised
		skip = pos
	}
}

func (r *Room) next(pos uint8) *Occupant {
	volume := r.Cap()
	for i := (pos) % volume; i != pos-1; i = (i + 1) % volume {
		if r.Occupants[i] != nil && r.Occupants[i].IsGameing() {
			return r.Occupants[i]
		}
	}
	return nil
}

func (r *Room) last(pos uint8) *Occupant {
	volume := r.Cap()

	for i := (pos-2+volume) % volume; i != pos-1; i = (i - 1+volume) % volume {
		if r.Occupants[i] != nil && r.Occupants[i].IsGameing() {
			return r.Occupants[i]
		}
	}
	return nil
}

func (r *Room) nextBetPos(pos uint8) uint8 {
	l := int(r.Len())
	for i := 0; i < l; i++ {
		if oc := r.next(pos);oc != nil && oc.chips > 0 {
			return oc.Pos
		}
	}
	return pos
}

//func (r *Room) GetReqRound2(timeout time.Duration) {
//	timer := time.NewTimer(timeout)
//	r.waitAction = true
//	select {
//	case <-r.reqRound2:
//		timer.Stop()
//		fmt.Println("reqRound2")
//		fmt.Println("reqRound2")
//		fmt.Println("reqRound2")
//		r.waitAction = false
//		close(r.reqRound2)
//
//	case <-timer.C:
//		r.waitAction = false
//		timer.Stop()
//	}
//}
//func (r *Room) GetReqRound3(timeout time.Duration) {
//	timer := time.NewTimer(timeout)
//	r.waitAction = true
//	select {
//	case <-r.reqRound3:
//		timer.Stop()
//		r.waitAction = false
//		close(r.reqRound3)
//
//	case <-timer.C:
//		r.waitAction = false
//		timer.Stop()
//	}
//}
//func (r *Room) GetReqRound4(timeout time.Duration) {
//	timer := time.NewTimer(timeout)
//	r.waitAction = true
//	select {
//	case <-r.reqRound4:
//		timer.Stop()
//		r.waitAction = false
//		close(r.reqRound4)
//
//	case <-timer.C:
//		r.waitAction = false
//		timer.Stop()
//	}
//}
//func (r *Room) GetReqResult(timeout time.Duration) {
//	timer := time.NewTimer(timeout)
//	r.waitAction = true
//	select {
//	case <-r.reqResult:
//		timer.Stop()
//		r.waitAction = false
//		close(r.reqResult)
//
//	case <-timer.C:
//		r.waitAction = false
//		timer.Stop()
//	}
//}